﻿using System;
using UnityEngine;
using UBlockly.Scriptable;
using System.Collections.Generic;
using UBlockly.Compotent;

namespace UBlockly.UI
{   
    public abstract class Node : IDisposable,IChangeNotify
    {
        private long id;
        public long Id => id;
        public BlockObject Block;
        public NodeScriptable Scriptable;
        public Action BodyChangeNotify;

        internal abstract bool IsDefaultParamNode { get; }

        public Node(BlockObject block, NodeScriptable script)
        {
            Scriptable = script;
            Block = block;
            if(block != null)
                Block.BindNode(this);
        }

        public virtual void Init()
        {
            this.id = ApplyNodeIndex();
            Block.name = "block-" + id;
            Block.GetSlotPair()?.SetBelongId(id);
        }

        public virtual void SetParamDisplayValue(IVarObject value)
        {
        }

        internal void ResizeNode()
        {
            Block.ReSize();
            if (Block.BlockType == BlockType.SlotType)
            {
                (Block.Node.List as ULinkedList<Node>)?.DoNotify();
            }
            else
            {
                OnChangeNotify();
            }
        }

        public bool IsBelongAnther()
        {
            if (Block == null)
                return true;
            bool isVoidTypeNode = Scriptable.ResultType == ILVarType.VoidR;
            bool isOnRoot = Block.Parent.name == Constant.NodeRootTransformName;
            if (!isVoidTypeNode && isOnRoot)  //嵌套类
                return false;
            if (isVoidTypeNode && isOnRoot && Block.Node.List.First.Value.id == id)
                return false;
            return true;
        }

        public bool IsAnChain()
        {
            return Block != null && Scriptable.ResultType == ILVarType.VoidR
                && Block.Node.List.Count != 0;
        }

        public virtual void Dispose()
        {
            Scriptable = null;
            if (Block != null)
               GameObject.Destroy(Block.gameObject);
        }

        /// <summary>
        /// 整个身体的节点，任何一个节点发生改变时，头都会响应到事件，然后重新计算
        /// 当前node为head时，才会被调用
        /// </summary>
        public void OnChangeNotify()
        {
            //Debug.LogError($"我是{id},我的一部分发生改变");
            (Block.Node.List as ULinkedList<Node>)?.PhysicSort();
            BodyChangeNotify?.Invoke();
        }

        static long startNodeIndex = 10000;
        static long ApplyNodeIndex()
        {
            return ++startNodeIndex;
        }
    }
}

